use pest::Parser;
use pest_derive::Parser;
use std::fs;

#[derive(Parser)]
#[grammar = "sysy.pest"]
pub struct SysYParser;

fn main() {
    let args: Vec<String> = std::env::args().collect();
    if args.len() != 2 {
        eprintln!("Usage: {} <filename>", args[0]);
        std::process::exit(1);
    }

    let filename = &args[1];
    let source_code = match fs::read_to_string(filename) {
        Ok(content) => content,
        Err(e) => {
            eprintln!("Error reading file {}: {}", filename, e);
            std::process::exit(1);
        }
    };

    // 先尝试解析看是否有错误
    match SysYParser::parse(Rule::program, &source_code) {
        Ok(mut pairs) => {
            // 没有错误，正常输出tokens
            let tokens = pairs.next().unwrap().into_inner();
            for token in tokens {
                // 递归处理 token 的内部规则
                if token.as_rule() == Rule::token {
                    for inner_token in token.into_inner() {
                        let line_no = inner_token.as_span().start_pos().line_col().0;
                        let token_str = inner_token.as_str();
                        match inner_token.as_rule() {
                            Rule::IDENT => {
                                eprintln!("IDENT {} at Line {}.", token_str, line_no);
                            }
                            Rule::INTEGER_CONST => {
                                let value = parse_integer_const(token_str);
                                eprintln!("INTEGER_CONST {} at Line {}.", value, line_no);
                            }
                            Rule::CONST => eprintln!("CONST const at Line {}.", line_no),
                            Rule::INT => eprintln!("INT int at Line {}.", line_no),
                            Rule::VOID => eprintln!("VOID void at Line {}.", line_no),
                            Rule::IF => eprintln!("IF if at Line {}.", line_no),
                            Rule::ELSE => eprintln!("ELSE else at Line {}.", line_no),
                            Rule::WHILE => eprintln!("WHILE while at Line {}.", line_no),
                            Rule::BREAK => eprintln!("BREAK break at Line {}.", line_no),
                            Rule::CONTINUE => eprintln!("CONTINUE continue at Line {}.", line_no),
                            Rule::RETURN => eprintln!("RETURN return at Line {}.", line_no),
                            Rule::PLUS => eprintln!("PLUS + at Line {}.", line_no),
                            Rule::MUL => eprintln!("MUL * at Line {}.", line_no),
                            Rule::DIV => eprintln!("DIV / at Line {}.", line_no),
                            Rule::MOD => eprintln!("MOD % at Line {}.", line_no),
                            Rule::ASSIGN => eprintln!("ASSIGN = at Line {}.", line_no),
                            Rule::EQ => eprintln!("EQ == at Line {}.", line_no),
                            Rule::NEQ => eprintln!("NEQ != at Line {}.", line_no),
                            Rule::LT => eprintln!("LT < at Line {}.", line_no),
                            Rule::GT => eprintln!("GT > at Line {}.", line_no),
                            Rule::LE => eprintln!("LE <= at Line {}.", line_no),
                            Rule::GE => eprintln!("GE >= at Line {}.", line_no),
                            Rule::AND => eprintln!("AND && at Line {}.", line_no),
                            Rule::OR => eprintln!("OR || at Line {}.", line_no),
                            Rule::L_PAREN => eprintln!("L_PAREN ( at Line {}.", line_no),
                            Rule::R_PAREN => eprintln!("R_PAREN ) at Line {}.", line_no),
                            Rule::L_BRACE => eprintln!("L_BRACE {{ at Line {}.", line_no),
                            Rule::R_BRACE => eprintln!("R_BRACE }} at Line {}.", line_no),
                            Rule::L_BRACKT => eprintln!("L_BRACKT [ at Line {}.", line_no),
                            Rule::R_BRACKT => eprintln!("R_BRACKT ] at Line {}.", line_no),
                            Rule::COMMA => eprintln!("COMMA , at Line {}.", line_no),
                            Rule::SEMICOLON => eprintln!("SEMICOLON ; at Line {}.", line_no),
                            Rule::MINUS => eprintln!("MINUS - at Line {}.", line_no),
                            Rule::NOT => eprintln!("NOT ! at Line {}.", line_no),
                            _ => {} // 忽略其他
                        }
                    }
                }
            }
        }
        Err(_) => {
            // 有错误，需要扫描所有错误
            scan_all_errors(&source_code);
            std::process::exit(1);
        }
    }
}

fn scan_all_errors(source_code: &str) {
    let mut current_pos = 0;
    let mut line_no = 1;

    while current_pos < source_code.len() {
        let remaining = &source_code[current_pos..];

        // 跳过空白字符
        if remaining.chars().next().unwrap().is_whitespace() {
            let ch = remaining.chars().next().unwrap();
            if ch == '\n' {
                line_no += 1;
            }
            current_pos += ch.len_utf8();
            continue;
        }

        // 尝试匹配注释
        if remaining.starts_with("//") {
            // 跳过行注释到行尾
            if let Some(newline_pos) = remaining.find('\n') {
                current_pos += newline_pos + 1;
                line_no += 1;
            } else {
                // 注释到文件末尾
                break;
            }
            continue;
        }

        if remaining.starts_with("/*") {
            // 跳过块注释
            if let Some(end_pos) = remaining.find("*/") {
                let comment = &remaining[..end_pos + 2];
                for c in comment.chars() {
                    if c == '\n' {
                        line_no += 1;
                    }
                }
                current_pos += end_pos + 2;
            } else {
                // 未闭合的块注释，跳到文件末尾
                break;
            }
            continue;
        }

        // 尝试匹配单个token
        if let Ok(pairs) = SysYParser::parse(Rule::token, remaining) {
            // 成功匹配到token，跳过这个token
            let token_str = pairs.as_str();
            current_pos += token_str.len();

            // 更新行号
            for c in token_str.chars() {
                if c == '\n' {
                    line_no += 1;
                }
            }
        } else {
            // 如果不能匹配token，就是错误字符
            let error_char = remaining.chars().next().unwrap();
            eprintln!(
                "Error type A at Line {}:Unexpected character '{}'",
                line_no, error_char
            );

            // 跳过这个错误字符
            current_pos += error_char.len_utf8();
            if error_char == '\n' {
                line_no += 1;
            }
        }
    }
}

fn parse_integer_const(s: &str) -> i64 {
    if s.starts_with("0x") || s.starts_with("0X") {
        // 十六进制
        i64::from_str_radix(&s[2..], 16).unwrap()
    } else if s.starts_with('0') && s.len() > 1 {
        // 尝试解析为八进制，如果失败则作为十进制
        let octal_part = &s[1..];
        if octal_part.chars().all(|c| c.is_ascii_digit() && c <= '7') {
            // 所有字符都是有效的八进制数字
            i64::from_str_radix(octal_part, 8).unwrap()
        } else {
            // 包含非八进制数字，作为十进制解析
            s.parse().unwrap()
        }
    } else {
        // 十进制
        s.parse().unwrap()
    }
}
